package com.deyuanyun.pic.settings.domain.util;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.beanutils.PropertyUtils;
import org.springframework.aop.framework.AopContext;
import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.aop.support.AopUtils;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import com.deyuanyun.pic.settings.support.biz.CodeUtil;

/**
 * 主要用于对结果对象中Code字段的翻译。
 * 实现原理是cglib动态代理，主要原因是因为生成的Domain不能改，里面的Code都是ID呢。直接连表查Code也不好。
 * 直接改了原本Code的ID为Name，略有点不好。未来要做漂亮的话，可以考虑动态给它加一个字段进去。但是这又涉及到导出Excel的注解哦.....
 * 
 * 反思：这玩意儿会不会玩的太深沉了。哎.....
 * 
 * 特别注意：如果在get方法中处理了Code，那么会导致返回无值。因为有一次值拷贝，值拷贝就调用了get方法。
 *      所以，只在自动生成的那一堆类上使用此类，其它类还是就在get方法中做吧。
 * 
 * @author ChenKui
 * @date 2016-06-29
 *
 */
public class DomainCodeInterceptor implements MethodInterceptor {

    //private Object target;

    /*
    static{//加这一句是因为如果当出现Date日期字段，如果为NULL，会报错。诡异的错误。
        ConvertUtilsBean convertUtilsBean = BeanUtilsBean.getInstance().getConvertUtils();
        convertUtilsBean.register(new SqlDateConverter(null), Date.class);
        convertUtilsBean.register(new BigDecimalConverter(null), BigDecimal.class);
        convertUtilsBean.register(new IntegerConverter(null), Integer.class);
        convertUtilsBean.register(new LongConverter(null), Long.class);
    }
    */
    /**
     * 创建代理对象
     * 
     * @param target
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <T> T newProxyInstance(T target) {
        //还可以把这个类做成单例的，提高性能....
        DomainCodeInterceptor dcc = new DomainCodeInterceptor();
        //dcc.target = target;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        // 回调方法
        enhancer.setCallback(dcc);
        // 创建代理对象
        T proxyInstance = (T)enhancer.create();
        //BeanCopier beanCopier = BeanCopier.create(target.getClass(), proxyInstance.getClass(), false);
        //CglibBeanCopierUtils.copyProperties(target, proxyInstance);
        try {//警惕这个地方的效率问题，用上面效率很好，但是有一个异常未解决。
            PropertyUtils.copyProperties(proxyInstance,target);
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        return proxyInstance;
    }
    
    /**
     * 给一个List创建代理对象。
     * 
     * @param list
     * @return
     */
    public static <T> List<T> newProxyInstance(List<T> list){
        //TODO lijun 原来这样写 会丢失分页信息

//        List<T> n_list = new ArrayList<>(list.size());
//        for (T item : list) {
//            n_list.add(newProxyInstance(item));
//        }
//        return n_list;
        //TODO lijun 这样使用代理对象所有set() get()方法会被调用
        for (int i=0;i<list.size();i++){
            list.set(i,newProxyInstance(list.get(i)));
        }
        return list;
    }
    
    @Override
    public Object intercept(Object obj, Method method, Object[] args,MethodProxy proxy) throws Throwable {
        
        Object ba = proxy.invokeSuper(obj, args);
        //这样反射调用可能效率会较低，值拷贝也影响效率。无耐啊，mybatis生成对象重写不了。难道需要自己去写ASM然后继承，然后把目标类作为属性？
        //Object ba = method.invoke(target, args);
        String methodName = method.getName();
        if(methodName.startsWith("get") && !"getId".equals(methodName)){
            if(ba != null && ba instanceof String){
                String id = (String)ba;
                if(id.length() == 32){//ID都是32位的
                    String val = CodeUtil.getName(id);
                    if(val != null){
                        ba = val;
                    }
                }
            }
        }
        return ba;
    }

    /*
    public <T> T wrap(T target){
        Object p = Proxy.newProxyInstance(target.getClass().getClassLoader(),
                new Class[] { target.getClass() },
                handler);
        return p;
    }
     */
    
}
